<?php
/**
 * The Action class
 */
abstract class LtAction
{
    /**
     * The context object
     * 
     * @var object 
     */
    public $context;
    public $viewDir;
    public $viewTplDir;
    public $viewTplAutoCompile;
    /**
     * The dtd config for validator
     * 
     * @var array 
     */
    protected $dtds = array();
    /**
     * The Access Control List
     * 
     * @var array 
     */
    protected $acl;
    /**
     * The current user's roles
     * 
     * @var array 
     */
    protected $roles = array();
    /**
     * A flag to indicate if subclass call LtAction::__construct()
     * 
     * @var boolean 
     */
    protected $constructed = false;
    /**
     * The response type
     * 
     * @var string 
     */
    protected $responseType = "html";
    /**
     * Result properties
     */
    protected $code;
    protected $message;
    public $data;
    protected $view;
    protected $layout;
    /**
     * The constructor function, initialize the URI property
     */
    public function __construct()
    {
        $this->constructed = true;
    }
    public function executeChain()
    {
        if (!$this->constructed) {
            //DebugHelper::debug('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR', array('class' => $actionClassName));
            trigger_error('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR');
        }
        $this->afterConstruct();
        $validateResult = $this->validateInput();
        if (0 == $validateResult["error_total"]) {
            if ($this->checkPrivilege()) {
                $this->beforeExecute();
                $this->execute();
            } else {
                $this->code    = 403;
                $this->message = "Access denied";
            }
        } else {
            $this->code                   = 407;
            $this->message                = "Invalid input";
            $this->data['error_messages'] = $validateResult["error_messages"];
        }
        $this->writeResponse();
    }
    /**
     * Do something after subClass::__construct().
     */
    protected function afterConstruct()
    {
    }
    /**
     * Validate the data from client
     * 
     * @return array 
     */
    protected function validateInput()
    {
        $validateResult = array(
            "error_total" => 0,
            "error_messages" => array()
        );
        if (!empty($this->dtds) && class_exists('LtValidator')) {
            $validator = new LtValidator;
            $validator->init();
            foreach ($this->dtds as $variable => $dtd) {
                $from = isset($dtd->from) ? $dtd->from : 'request';
                foreach ($dtd->rules as $ruleKey => $ruleValue) {
                    if ($ruleValue instanceof ConfigExpression) {
                        eval('$_ruleValue = ' . $ruleValue->__toString());
                        $dtd->rules[$ruleKey] = $_ruleValue;
                    }
                }
                $error_messages = $validator->validate($this->context->$from($variable), $dtd);
                if (!empty($error_messages)) {
                    $validateResult['error_total']++;
                    $validateResult['error_messages'][$variable] = $error_messages;
                }
            }
        }
        return $validateResult;
    }
    /**
     * Check if current user have privilege to do this
     * 
     * @return boolen 
     */
    protected function checkPrivilege()
    {
        $allow = true;
        if (!empty($this->roles) && class_exists('LtRbac')) {
            $module = $this->context->uri["module"];
            $action = $this->context->uri["action"];
            $roles  = array_merge(array(
                "*"
            ), $this->roles);
            $rbac   = new LtRbac();
            $rbac->init();
            $allow = $rbac->checkAcl($roles, "$module/$action");
        }
        return $allow;
    }
    /**
     * Do something before subClass::execute().
     */
    protected function beforeExecute()
    {
    }
    protected function execute()
    {
    }
    protected function writeResponse()
    {
        switch ($this->responseType) {
            case 'json':
                echo json_encode(array(
                    "code" => $this->code,
                    "message" => $this->message,
                    "data" => $this->data
                ));
                exit; //
                break;
            case 'tpl':
                if (null === $this->view) {
                    $this->view = new LtTemplateView;
                }
                $this->view->component   = false; // 是否组件
                $this->view->context     = $this->context;
                $this->view->code        = $this->code;
                $this->view->message     = $this->message;
                $this->view->data        = $this->data;
                $this->view->layoutDir   = $this->viewDir . "layout/";
                $this->view->layout      = $this->layout;
                $this->view->templateDir = $this->viewDir;
                $this->view->compiledDir = $this->viewTplDir;
                $this->view->autoCompile = $this->viewTplAutoCompile;
                if (empty($this->template)) {
                    $this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
                }
                $this->view->template = $this->template;
                $this->view->render();
                break;
            case 'html':
            case 'wml':
            default:
                if (null === $this->view) {
                    $this->view = new LtView;
                }
                $this->view->context     = $this->context;
                $this->view->code        = $this->code;
                $this->view->message     = $this->message;
                $this->view->data        = $this->data;
                $this->view->layoutDir   = $this->viewDir . "layout/";
                $this->view->layout      = $this->layout;
                $this->view->templateDir = $this->viewDir;
                if (empty($this->template)) {
                    $this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
                }
                $this->view->template = $this->template;
                $this->view->render();
                break;
        }
    }
}
